#!/bin/bash
log-helper level eq trace && set -x

# This tool helps to generate tls certificates with cfssl
# It takes cfssl configuration from environment variable.
# See cfssl-default-env file

PREFIX=$1
CERT_FILE=$2
KEY_FILE=$3
CA_FILE=$4

log-helper debug "cfssl-helper is launched, everybody on the floor!"

# before 0.2.5 retro compatibility, will be removed.
mkdir -p "${CONTAINER_SERVICE_DIR}/:cfssl/assets/default-ca"
ln -sf "${CONTAINER_SERVICE_DIR}/:ssl-tools/assets/default-ca/default-ca.pem" "${CONTAINER_SERVICE_DIR}/:cfssl/assets/default-ca/default-ca.pem"

if [ -z "${PREFIX}" ] || [ -z "${CERT_FILE}" ] || [ -z "${KEY_FILE}" ] || [ -z "${CA_FILE}" ]; then
    log-helper error "Usage: cfssl-helper prefix cert_file key_file ca_file"
    exit 1
fi

if [ ! -e "${CERT_FILE}" ] && [ ! -e "${KEY_FILE}" ]; then
    
    log-helper info "No certificate file and certificate key provided, generate:"
    log-helper info "${CERT_FILE} and ${KEY_FILE}"
    
    LOG_LEVEL_PARAM=""
    
    case ${CONTAINER_LOG_LEVEL} in
        0 )
        LOG_LEVEL_PARAM="-loglevel 4";;
        1 )
        LOG_LEVEL_PARAM="-loglevel 3";;
        2 )
        LOG_LEVEL_PARAM="-loglevel 2";;
        3 )
        LOG_LEVEL_PARAM="-loglevel 1";;
        4 )
        LOG_LEVEL_PARAM="-loglevel 0";;
        5 )
        LOG_LEVEL_PARAM="-loglevel 0";;
    esac
    
    # set env vars
    PREFIX=${PREFIX^^} # uppercase
    
    # search for prefixed env var first
    
    # set prefix variable name
    # example : PREFIX_CFSSL_REMOTE='MARIADB_CFSSL_REMOTE'
    PREFIX_CFSSL_REMOTE=${PREFIX}_CFSSL_REMOTE
    PREFIX_CFSSL_REMOTE_HTTPS_CA_CERT=${PREFIX}_CFSSL_REMOTE_HTTPS_CA_CERT
    PREFIX_CFSSL_CA_CERT=${PREFIX}_CFSSL_CA_CERT
    PREFIX_CFSSL_CA_KEY=${PREFIX}_CFSSL_CA_KEY
    PREFIX_CFSSL_CSR=${PREFIX}_CFSSL_CSR
    PREFIX_CFSSL_CSR_JSON=${PREFIX}_CFSSL_CSR_JSON
    PREFIX_CFSSL_CONFIG=${PREFIX}_CFSSL_CONFIG
    PREFIX_CFSSL_CONFIG_JSON=${PREFIX}_CFSSL_CONFIG_JSON
    PREFIX_CFSSL_HOSTNAME=${PREFIX}_CFSSL_HOSTNAME
    PREFIX_CFSSL_PROFILE=${PREFIX}_CFSSL_PROFILE
    PREFIX_CFSSL_LABEL=${PREFIX}_CFSSL_LABEL
    PREFIX_CFSSL_RETRY=${PREFIX}_CFSSL_RETRY
    PREFIX_CFSSL_RETRY_DELAY=${PREFIX}_CFSSL_RETRY_DELAY
    
    # assign CFSSL_REMOTE=${!PREFIX_CFSSL_REMOTE} if value is not empty otherwise CFSSL_REMOTE=CFSSL_REMOTE
    CFSSL_REMOTE=${!PREFIX_CFSSL_REMOTE:-$CFSSL_REMOTE}
    CFSSL_REMOTE_HTTPS_CA_CERT=${!PREFIX_CFSSL_REMOTE_HTTPS_CA_CERT:-$CFSSL_REMOTE_HTTPS_CA_CERT}
    CFSSL_CA_CERT=${!PREFIX_CFSSL_CA_CERT:-$CFSSL_CA_CERT}
    CFSSL_CA_KEY=${!PREFIX_CFSSL_CA_KEY:-$CFSSL_CA_KEY}
    CFSSL_CSR=${!PREFIX_CFSSL_CSR:-$CFSSL_CSR}
    CFSSL_CSR_JSON=${!PREFIX_CFSSL_CSR_JSON:-$CFSSL_CSR_JSON}
    CFSSL_CONFIG=${!PREFIX_CFSSL_CONFIG:-$CFSSL_CONFIG}
    CFSSL_CONFIG_JSON=${!PREFIX_CFSSL_CONFIG_JSON:-$CFSSL_CONFIG_JSON}
    CFSSL_HOSTNAME=${!PREFIX_CFSSL_HOSTNAME:-$CFSSL_HOSTNAME}
    CFSSL_PROFILE=${!PREFIX_CFSSL_PROFILE:-$CFSSL_PROFILE}
    CFSSL_LABEL=${!PREFIX_CFSSL_LABEL:-$CFSSL_LABEL}
    CFSSL_RETRY=${!PREFIX_CFSSL_RETRY:-$CFSSL_RETRY}
    CFSSL_RETRY_DELAY=${!PREFIX_CFSSL_RETRY_DELAY:-$CFSSL_RETRY_DELAY}
    
    source "${CONTAINER_SERVICE_DIR}/:ssl-tools/assets/cfssl-default-env"
    
    # set csr file
    CSR_FILE="/tmp/csr-file"
    if [ -n "${CFSSL_CSR_JSON}" ]; then
        log-helper debug "use CFSSL_CSR_JSON value as csr file"
        echo "${CFSSL_CSR_JSON}" > "${CSR_FILE}"
        elif [ -n "${CFSSL_CSR}" ]; then
        log-helper debug "use ${CFSSL_CSR} as csr file"
        cp -f "${CFSSL_CSR}" "${CSR_FILE}"
        
        # it's the default csr
        if [ "${CFSSL_CSR}" = "${CFSSL_DEFAULT_CSR}" ]; then
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_CN }}|${CFSSL_DEFAULT_CA_CSR_CN}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_KEY_ALGO }}|${CFSSL_DEFAULT_CA_CSR_KEY_ALGO}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_KEY_SIZE }}|${CFSSL_DEFAULT_CA_CSR_KEY_SIZE}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_CERT_ORGANIZATION_UNIT }}|${CFSSL_CERT_ORGANIZATION_UNIT}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_ORGANIZATION }}|${CFSSL_DEFAULT_CA_CSR_ORGANIZATION}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_ORGANIZATION_UNIT }}|${CFSSL_DEFAULT_CA_CSR_ORGANIZATION_UNIT}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_LOCATION }}|${CFSSL_DEFAULT_CA_CSR_LOCATION}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_STATE }}|${CFSSL_DEFAULT_CA_CSR_STATE}|g" "${CSR_FILE}"
            sed -i "s|{{ CFSSL_DEFAULT_CA_CSR_COUNTRY }}|${CFSSL_DEFAULT_CA_CSR_COUNTRY}|g" "${CSR_FILE}"
        fi
    else
        log-helper error "error: no csr file provided"
        log-helper error "CFSSL_CSR_JSON and CFSSL_CSR are empty"
        exit 1
    fi
    
    # generate cert
    CONFIG_FILE="/tmp/config-file"
    CERT_NAME="cert"
    
    REMOTE_PARAM=""
    CA_CERT_PARAM=""
    CA_KEY_PARAM=""
    CONFIG_PARAM=""
    HOSTNAME_PARAM=""
    PROFILE_PARAM=""
    LABEL_PARAM=""
    
    if [ -n "${CFSSL_REMOTE}" ]; then
        REMOTE_PARAM="-remote=${CFSSL_REMOTE}"
        
        # add remote https ca cert to known certificates if not empty
        if [ -n "${CFSSL_REMOTE_HTTPS_CA_CERT}" ]; then
            if [ -e "${CFSSL_REMOTE_HTTPS_CA_CERT}" ]; then
                [[ ! -d "/etc/ssl/certs/" ]] && mkdir -p /etc/ssl/certs/
                cat "${CFSSL_REMOTE_HTTPS_CA_CERT}" >> /etc/ssl/certs/ca-certificates.crt
            else
                log-helper error "error: remote https ca cert file ${CFSSL_REMOTE_HTTPS_CA_CERT} not found"
            fi
        fi
        
    else
        
        # files path with : may cause issue with cfssl tools due to :
        # ReadBytes - https://github.com/cloudflare/cfssl/blob/master/helpers/helpers.go#L573
        # : is used to split env from file path
        # so we copy ca cert and key to tmp
        if [ -n "${CFSSL_CA_CERT}" ]; then
            
            CFSSL_CA_CERT_FILE="/tmp/ca-cert-file"
            cp -f "${CFSSL_CA_CERT}" "${CFSSL_CA_CERT_FILE}"
            chmod 644 "${CFSSL_CA_CERT_FILE}"
            
            CA_CERT_PARAM="-ca ${CFSSL_CA_CERT_FILE}"
        fi
        
        if [ -n "${CFSSL_CA_KEY}" ]; then
            
            CFSSL_CA_KEY_FILE="/tmp/ca-key-file"
            cp -f "${CFSSL_CA_KEY}" "${CFSSL_CA_KEY_FILE}"
            chmod 600 "${CFSSL_CA_CERT_FILE}"
            
            CA_KEY_PARAM="-ca-key ${CFSSL_CA_KEY_FILE}"
        fi
        
    fi
    
    if [ -n "${CFSSL_CONFIG_JSON}" ]; then
        log-helper debug "use CFSSL_CONFIG_JSON value as config file"
        echo "${CFSSL_CONFIG_JSON}" > "${CONFIG_FILE}"
        CONFIG_PARAM="-config ${CONFIG_FILE}"
        
        elif [ -n "${CFSSL_CONFIG}" ]; then
        log-helper debug "use ${CFSSL_CONFIG} as config file"
        cp -f "${CFSSL_CONFIG}" "${CONFIG_FILE}"
        CONFIG_PARAM="-config ${CONFIG_FILE}"
    fi

    if [ -n "$ADDITIONAL_HOSTNAMES" ]; then
        log-helper debug "additional hostnames found"
        CFSSL_HOSTNAME="${CFSSL_HOSTNAME},${ADDITIONAL_HOSTNAMES}"
    fi
    
    [[ -n "${CFSSL_HOSTNAME}" ]] && HOSTNAME_PARAM="-hostname ${CFSSL_HOSTNAME}"
    [[ -n "${CFSSL_PROFILE}" ]] && PROFILE_PARAM="-profile ${CFSSL_PROFILE}"
    [[ -n "${CFSSL_LABEL}" ]] && LABEL_PARAM="-label ${CFSSL_LABEL}"
    
    retry=0
    while [  $retry -lt "${CFSSL_RETRY}" ]; do
        log-helper debug "cfssl gencert ${LOG_LEVEL_PARAM} ${REMOTE_PARAM} ${CA_CERT_PARAM} ${CA_KEY_PARAM} ${CONFIG_PARAM} ${HOSTNAME_PARAM} ${PROFILE_PARAM} ${LABEL_PARAM} ${CSR_FILE} | cfssljson -bare /tmp/${CERT_NAME}"
        eval cfssl gencert "${LOG_LEVEL_PARAM}" "${REMOTE_PARAM}" "${CA_CERT_PARAM}" "${CA_KEY_PARAM}" "${CONFIG_PARAM}" "${HOSTNAME_PARAM}" "${PROFILE_PARAM}" "${LABEL_PARAM}" "${CSR_FILE}" | cfssljson -bare "/tmp/${CERT_NAME}" && break
        sleep "${CFSSL_RETRY_DELAY}"
        ((retry++))
    done
    
    # move generated files
    [[ ! -e "/tmp/${CERT_NAME}.pem" ]] && exit 1
    log-helper debug "move /tmp/${CERT_NAME}.pem to ${CERT_FILE}"
    mv "/tmp/${CERT_NAME}.pem" "${CERT_FILE}"
    
    log-helper debug "move /tmp/${CERT_NAME}-key.pem to ${KEY_FILE}"
    mv "/tmp/${CERT_NAME}-key.pem" "${KEY_FILE}"
    
    # if ca file don't exists
    if [ ! -e "${CA_FILE}" ]; then
        
        if [ -n "${CFSSL_REMOTE}" ]; then
            log-helper debug "Get CA certificate from ${CFSSL_REMOTE}"
            
            retry=0
            while [  $retry -lt "${CFSSL_RETRY}" ]; do
                log-helper debug "cfssl info ${LOG_LEVEL_PARAM} ${REMOTE_PARAM} ${CONFIG_PARAM} ${PROFILE_PARAM} ${LABEL_PARAM}"
                eval cfssl info "${LOG_LEVEL_PARAM}" "${REMOTE_PARAM}" "${CONFIG_PARAM}" "${PROFILE_PARAM}" "${LABEL_PARAM}" | sed -e "s/.*certificate\":\"\(.*-----\)\".*/\1/g" | sed 's/\\n/\n/g' > "${CA_FILE}" && log-helper debug "CA certificate returned save as ${CA_FILE}" && break
                sleep "${CFSSL_RETRY_DELAY}"
                ((retry++))
            done
            
            [[ ! -e "${CA_FILE}" ]] && exit 1
            
            elif [ -n "${CFSSL_CA_CERT}" ]; then
            log-helper info "Link ${CFSSL_CA_CERT} to ${CA_FILE}"
            ln -sf "${CFSSL_CA_CERT}" "${CA_FILE}"
        fi
        
    fi
    
    # delete tmp files
    rm -f /tmp/${CERT_NAME}.csr ${CONFIG_FILE} "${CSR_FILE}"
    [[ -e "${CFSSL_CA_CERT_FILE}" ]] && rm "${CFSSL_CA_CERT_FILE}"
    [[ -e "${CFSSL_CA_KEY_FILE}" ]] && rm "${CFSSL_CA_KEY_FILE}"
    
    log-helper debug "done :)"
    
    elif [ ! -e "${KEY_FILE}" ]; then
    log-helper error "Certificate file ${CERT_FILE} exists but not key file ${KEY_FILE}"
    exit 1
    elif [ ! -e "${CERT_FILE}" ]; then
    log-helper error "Key file ${KEY_FILE} exists but not certificate file ${CERT_FILE}"
    exit 1
else
    log-helper debug "Files ${CERT_FILE} and ${KEY_FILE} exists, fix files permissions"
    chmod 644 "${CERT_FILE}"
    chmod 600 "${KEY_FILE}"
fi
